﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tomlyn.Model;
using Tomlyn;
using KaroglanSharedLib;

namespace KaroglanLauncher
{
    public class FabricModInfo
    {
        public int schemaVersion { get; set; }
        public string id { get; set; }
        public string version { get; set; }
        public string name { get; set; }
        public string description { get; set; }
        public List<string> authors { get; set; }
        public string license { get; set; }
        public string icon { get; set; }
        public string environment { get; set; }
    }

    public class ModObj
    {

        
        public string modID;
        public bool isCoreMod => fileFullPath.Contains("[OPT]");

        public string type => string.IsNullOrEmpty(_type) ? ModManager.UNDEFINED : _type;
        private string _type;
        public void SetType(string modType)
        {
            _type = modType;
        }

        public string displayName => string.IsNullOrEmpty(_displayName) ? ModManager.UNDEFINED : _displayName;
        private string _displayName;

        public string fileFullPath => _fileFullPath;
        private string _fileFullPath;

        public void SetFullPath(string modFullPath)
        {
            _fileFullPath = modFullPath;
        }

        public bool enabled => enabled;
        private bool _enabled;
        public List<string> requiredMod;

        private ModObj(string id, string path)
        {
            modID = id;
            _fileFullPath = path;
        }

        public static ModObj ParseFromPath(string modPath)
        {
            if (!File.Exists(modPath)) return null;
            //File name template is [OPT][TYPE][DISPLAYNAME]modID-version.jar(.disabled)
            var fileName = Path.GetFileName(modPath);
            var nameElement = fileName.Split(']').Select(str => str.Replace("[","")).ToArray();
            var modType = nameElement.Length > 2 ? nameElement[1].Replace("[", "") : ModManager.UNDEFINED;
            var modDisplayName = nameElement.Length > 3 ? nameElement[2].Replace("[", "") : ModManager.UNDEFINED;
            var nameVer = nameElement.Length > 3 ? nameElement[3];
            var n
            var enabled = modPath.EndsWith(".jar");
            return new ModObj()
        }

        public void ParseInfoFromPath()
        {
        }
        
        public static ModObj GetFromPath(string filePath)
        {
            if (File.Exists(filePath))
            {
                using (ZipArchive archive = ZipFile.OpenRead(filePath))
                {
                    // Try load forge mod
                    ZipArchiveEntry manifestEntry = archive.GetEntry("META-INF/mods.toml");
                    if (manifestEntry != null)
                    {
                        // 读取MANIFEST.MF文件的内容
                        using (StreamReader reader = new StreamReader(manifestEntry.Open()))
                        {
                            string manifestContent = reader.ReadToEnd();

                            var toml = Toml.ToModel(manifestContent);

                            var modSec = toml["mods"];
                            string modID = "";
                            if (modSec is TomlArray)
                            {
                                var baseData = ((TomlTable)((TomlArray)modSec)[0]);
                                if (baseData["displayName"] != null) modID = baseData["displayName"].ToString();
                                else modID = baseData["modId"].ToString();
                            }
                            else if (modSec is TomlTableArray)
                            {
                                var baseData = ((TomlTableArray)modSec)[0];
                                if (baseData["displayName"] != null) modID = baseData["displayName"].ToString();
                                else modID = baseData["modId"].ToString();
                            }

                            if (string.IsNullOrEmpty(modID))
                            {
                                throw new Exception($"无法解析ModId：{filePath}");
                            }
                            return new ModObj(modID, filePath);
                        }
                    }
                    else
                    {
                        //Parse Fabric Mod
                        ZipArchiveEntry fabricModInfoEntry = archive.GetEntry("fabric.mod.json");
                        if (fabricModInfoEntry != null)
                        {
                            ModObj modObj = new ModObj();
                            // 读取MANIFEST.MF文件的内容
                            using (StreamReader reader = new StreamReader(fabricModInfoEntry.Open()))
                            {
                                string rawModInfo = reader.ReadToEnd();

                                var json = JsonConvert.DeserializeObject<FabricModInfo>(rawModInfo);
                                if (json != null)
                                {
                                    modObj.modID = json.id;
                                    modObj.SetFullPath(filePath);
                                    modObj.ParseInfoFromPath();
                                }
                            }
                            return modObj;
                        }
                        else
                        {
                            ModObj modObj = new ModObj();
                            modObj.isCoreMod = !path.Contains("[OPT]");
                            var FileName = Path.GetFileName(path);
                            var nameMeta = FileName.Split(']');
                            if (nameMeta.Length > 1) modObj.type = nameMeta[1].Replace("[", "");
                            if (nameMeta.Length > 2) modObj.displayName = nameMeta[2].Replace("[", "");
                            modObj.requiredMod = new List<string>();
                            modObj.enabled = path.EndsWith(".jar");
                            modObj.fileName = FileName;
                            try
                            {
                                modObj.modID = nameMeta[nameMeta.Length - 1].Split('-')[0];
                                return modObj;
                            }
                            catch (Exception)
                            {
                                return modObj;
                            }
                        }
                    }
                }
            }
            else return null;
        }
        
        public string fileName => Path.GetFileName(fileFullPath);
        public string fileNameWithoutExtention => Path.GetFileNameWithoutExtension(fileFullPath);

        public bool SetEnable(bool newState)
        {
            try
            {
                if (string.IsNullOrEmpty(fileFullPath)) return false;
                if (enabled == newState) return true;

                string targetPath = newState ? fileFullPath.Replace(ModManager.DISABLEDSUFFIX,"") : $"{fileFullPath}{ModManager.DISABLEDSUFFIX}";
                
                File.Move(fileFullPath, targetPath);

                _enabled = newState;
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public void Rename()
        {
            var targetFileName = $"[{(isCoreMod? ModManager.COREMODPREFIX :ModManager.NOTCOREMODPREFIX)}][{type}][{displayName}]{modID}-{version}.jar{(enabled ? string.Empty : ModManager.DISABLEDSUFFIX)}";
            var targetFullPath = Path.Combine(Path.GetDirectoryName(fileFullPath), targetFileName);
            
            if (Utils.ArePathsPointingToSameFile(targetFullPath,fileFullPath)) return;
            if (File.Exists(targetFullPath))
            {
                File.Delete(targetFullPath);
            }

            File.Move(fileFullPath, targetFileName);
        }
    }

    public class ModManager
    {
        private static Dictionary<string, ModObj> Data;
        public const string DISABLEDSUFFIX = ".disabled";
        public const string COREMODPREFIX = "核心";
        public const string NOTCOREMODPREFIX = "可选";
        public static string UNDEFINED = "未定义";

        public static Dictionary<string, ModObj> GetData()
        {
            if (Data == null) ReloadData();
            return Data;
        }

        public static void ReloadData()
        {
            var rawData = File.ReadAllText(GetModInfoCachePath());
            Data = JsonConvert.DeserializeObject<Dictionary<string, ModObj>>(rawData);
            if (Data == null) Data = new Dictionary<string, ModObj>();
        }

        public static bool UpdateModDict()
        {
            var modInfos = new List<ModObj>();
            var modPaths = Directory.GetFiles(Utils.GetModsFolder(), "*.jar*", SearchOption.TopDirectoryOnly);
            foreach (var modPath in modPaths)
            {
                var modInfo = CalculateModInfo(modPath);
                if (modInfo != null) modInfos.Add(modInfo);
            }

            var dict = GetData();
            foreach (var modInfo in modInfos)
            {
                var modID = modInfo.modID;
                if (dict.Keys.Contains(modID)) 
                { 
                    var targetInfo = dict[modID];
                    targetInfo.enabled = modInfo.enabled; 
                    targetInfo.displayName = modInfo.displayName;
                    targetInfo.type = modInfo.type;

                }
                else dict.Add(modID, modInfo);
            }

            SaveModInfoCache(dict);
            ReloadData();
            return true;
        }

        public static string GetModInfoCachePath()
        {
            var result = Path.Combine(Utils.GetToolsFolder(), "modInfo.json");
            if (!File.Exists(result))
            {
                File.WriteAllText(result, "");
            }
            return result;
        }

        public static void SaveModInfoCache(Dictionary<string, ModObj> dict)
        {
            var rawData = JsonConvert.SerializeObject(dict);
            File.WriteAllText(GetModInfoCachePath(), rawData);
        }

        public static ModObj CalculateModInfo(string path)
        {
        }

    }
}
